 /*!@defgroup client Cliente
 * @brief Módulo Cliente
 */

/** @{ */
 
 /*!@file client.c
 *@brief Go Back N - Parte do Servidor
 *@author Igor Coelho
 *@author Thiago Stuckert
 *@date 09  de Maio
 *@version 0.1 
 */

/*Para compilar digite: gcc -o server server.c  -g */
/*Para rodar digite: ./server */

 
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>

#define PORT 5687
#define BACKLOG 5
#define packet_size 64
#define buffer_size 1024
#define debug printf
#define N 10
int main(void) {
	int sock, yes = 1, aux;
	struct sockaddr_in addr;
	unsigned int size = sizeof addr;
        char packet[packet_size];
	char *data;
        char *checksum;
        int seqnumreceived;
        int expectedseqnum=0;
        int ACK;
        
	/* Cria o socket. */
	sock = socket(PF_INET, SOCK_DGRAM, 0);
	if (sock == -1) {
		perror("Não conseguiu criar o socket do servidor.");
		return EXIT_FAILURE;
	}

	/* Permite que o socket escute na porta, a não ser que já tenha alguém escutando nela. */
	aux = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes);
	if (aux == -1) {
		perror("Não conseguiu reutilizar a porta de conexão.");
		return EXIT_FAILURE;
	}

	/* Cria o endereço do socket. */
	addr.sin_family = AF_INET;
	addr.sin_port = htons(PORT);
	addr.sin_addr.s_addr = INADDR_ANY;
	memset(&addr.sin_zero, 0, 8);

	/* Associa o socket ao seu endereço. */
	if (bind(sock, (struct sockaddr *) &addr, sizeof addr) == -1) {
		perror("Não conseguiu fazer o bind do socket do servidor com a porta.");
		return EXIT_FAILURE;
	}
        /*No livro na pagina 172 ta falando para enviar um pacote inicial*/
	/* Fica em loop infinito recebendo e enviando de volta os pacotes do cliente */
	for (;;) {
                
		aux = recvfrom(sock, packet, packet_size , 0, (struct sockaddr *) &addr, &size);
		if (aux <= 0) {
			perror("Erro ao receber mensagem");
			return EXIT_FAILURE;
		}
                seqnumreceived = atoi(strtok (packet," "));
                data = strtok (NULL, " ");
                checksum = strtok (NULL, " ");
                printf("Packet received %d %s %s\n",seqnumreceived,data,checksum);
                
                /*Apos recebermos o pacote devemos verificar tres coisas*/
                
                /*Primeira coisa se o pacote nao esta corrompido*/
                /*Ou seja deveriamos utilizarmos algum checksum como: 
                http://en.wikipedia.org/wiki/Adler-32*/
                /*vamos deixar essa parte se sobrar tempo a gente faz*/
                
                /*O pacote que chegou contem o numero de sequencia esperado*/
                
                if(expectedseqnum==seqnumreceived){
                    printf("Entrego o dado para a camada de aplicacao\n");
                    /*deliver_data(data);*/
                    /*sndpkt= make_pkt(expectedseqnum,ACK,checksum)*/
                    ACK=expectedseqnum;
                    sprintf(packet,"%d %d %s\n",expectedseqnum,ACK,"checksum");
                    expectedseqnum++;
                    aux = sendto(sock, packet, packet_size, 0, (struct sockaddr *) &addr, size);
        	    if (aux <= 0) {
	               perror("Erro ao enviar mensagem");
		       return EXIT_FAILURE;
		    }
                    /*Caso eu tenha recebido o ultimo pacote da janela 
                    devo esperar o primeiro da proxima janela*/
                    if(expectedseqnum==N){
                        expectedseqnum=0;   
                    }
                }else{
                    printf("Descarto o pacote recebido fora de ordem?\n");    
                    /*
                    sprintf(packet,"%d %s %s\n",expectedseqnum,"Quero esse pacote Porra!","checksum");
                    aux = sendto(sock, packet, packet_size, 0, (struct sockaddr *) &addr, size);
        	    if (aux <= 0) {
	               perror("Erro ao enviar mensagem");
		       return EXIT_FAILURE;
		    }
                    */
                }

                
	}

	close(sock);
	return 0;
}
